// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// FREE SOURCE CODE
// http://www.magic-software.com/License/free.pdf

#include "MgcVector2.h"

const MgcVector2 MgcVector2::ZERO(0,0);
const MgcVector2 MgcVector2::UNIT_X(1,0);
const MgcVector2 MgcVector2::UNIT_Y(0,1);

//----------------------------------------------------------------------------
MgcVector2::MgcVector2 ()
{
    // For efficiency in construction of large arrays of vectors, the
    // default constructor does not initialize the vector.
}
//----------------------------------------------------------------------------
MgcVector2::MgcVector2 (MgcReal fX, MgcReal fY)
{
    x = fX;
    y = fY;
}
//----------------------------------------------------------------------------
MgcVector2::MgcVector2 (MgcReal afCoordinate[2])
{
    x = afCoordinate[0];
    y = afCoordinate[1];
}
//----------------------------------------------------------------------------
MgcVector2::MgcVector2 (const MgcVector2& rkVector)
{
    x = rkVector.x;
    y = rkVector.y;
}
//----------------------------------------------------------------------------
MgcReal& MgcVector2::operator[] (int i) const
{
    // assert:  0 <= i < 2; x and y are packed into 2*sizeof(MgcReal) bytes
    return (MgcReal&) *(&x + i);
}
//----------------------------------------------------------------------------
MgcVector2::operator MgcReal* ()
{
    return &x;
}
//----------------------------------------------------------------------------
MgcVector2& MgcVector2::operator= (const MgcVector2& rkVector)
{
    x = rkVector.x;
    y = rkVector.y;
    return *this;
}
//----------------------------------------------------------------------------
bool MgcVector2::operator== (const MgcVector2& rkVector) const
{
    return ( x == rkVector.x && y == rkVector.y );
}
//----------------------------------------------------------------------------
bool MgcVector2::operator!= (const MgcVector2& rkVector) const
{
    return ( x != rkVector.x || y != rkVector.y );
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::operator+ (const MgcVector2& rkVector) const
{
    MgcVector2 kSum;
    kSum.x = x + rkVector.x;
    kSum.y = y + rkVector.y;
    return kSum;
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::operator- (const MgcVector2& rkVector) const
{
    MgcVector2 kDiff;
    kDiff.x = x - rkVector.x;
    kDiff.y = y - rkVector.y;
    return kDiff;
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::operator* (MgcReal fScalar) const
{
    MgcVector2 kProd;
    kProd.x = fScalar*x;
    kProd.y = fScalar*y;
    return kProd;
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::operator- () const
{
    MgcVector2 kNeg;
    kNeg.x = -x;
    kNeg.y = -y;
    return kNeg;
}
//----------------------------------------------------------------------------
MgcVector2 operator* (MgcReal fScalar, const MgcVector2& rkVector)
{
    MgcVector2 kProd;
    kProd.x = fScalar*rkVector.x;
    kProd.y = fScalar*rkVector.y;
    return kProd;
}
//----------------------------------------------------------------------------
MgcVector2& MgcVector2::operator+= (const MgcVector2& rkVector)
{
    x += rkVector.x;
    y += rkVector.y;
    return *this;
}
//----------------------------------------------------------------------------
MgcVector2& MgcVector2::operator-= (const MgcVector2& rkVector)
{
    x -= rkVector.x;
    y -= rkVector.y;
    return *this;
}
//----------------------------------------------------------------------------
MgcVector2& MgcVector2::operator*= (MgcReal fScalar)
{
    x *= fScalar;
    y *= fScalar;
    return *this;
}
//----------------------------------------------------------------------------
MgcReal MgcVector2::SquaredLength () const
{
    return x*x + y*y;
}
//----------------------------------------------------------------------------
MgcReal MgcVector2::Dot (const MgcVector2& rkVector) const
{
    return x*rkVector.x + y*rkVector.y;
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::operator/ (MgcReal fScalar) const
{
    MgcVector2 kQuot;

    if ( fScalar != 0.0 )
    {
        MgcReal fInvScalar = 1.0/fScalar;
        kQuot.x = fInvScalar*x;
        kQuot.y = fInvScalar*y;
        return kQuot;
    }
    else
    {
        return MgcVector2(MgcMath::INFINITY,MgcMath::INFINITY);
    }
}
//----------------------------------------------------------------------------
MgcVector2& MgcVector2::operator/= (MgcReal fScalar)
{
    if ( fScalar != 0.0 )
    {
        MgcReal fInvScalar = 1.0/fScalar;
        x *= fInvScalar;
        y *= fInvScalar;
    }
    else
    {
        x = MgcMath::INFINITY;
        y = MgcMath::INFINITY;
    }

    return *this;
}
//----------------------------------------------------------------------------
MgcReal MgcVector2::Length () const
{
    return MgcMath::Sqrt(x*x +y*y);
}
//----------------------------------------------------------------------------
MgcReal MgcVector2::Unitize (MgcReal fTolerance)
{
    MgcReal fLength = Length();

    if ( fLength > fTolerance )
    {
        MgcReal fInvLength = 1.0/fLength;
        x *= fInvLength;
        y *= fInvLength;
    }
    else
    {
        fLength = 0.0;
    }

    return fLength;
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::Cross () const
{
    // vector orthogonal to (x,y) is (y,-x)
    MgcVector2 kCross;
    kCross.x = y;
    kCross.y = -x;
    return kCross;
}
//----------------------------------------------------------------------------
MgcVector2 MgcVector2::UnitCross () const
{
    // unit vector orthogonal to (x,y) is (y,-x)/sqrt(x^2+y^2)
    MgcVector2 kCross;
    kCross.x = y;
    kCross.y = -x;
    kCross.Unitize();
    return kCross;
}
//----------------------------------------------------------------------------
void MgcVector2::Orthonormalize (MgcVector2 akVector[2])
{
    // If the input vectors are v0 and v1, then the Gram-Schmidt
    // orthonormalization produces vectors u0 and u1 as follows,
    //
    //   u0 = v0/|v0|
    //   u1 = (v1-(u0*v1)u0)/|v1-(u0*v1)u0|
    //
    // where |A| indicates length of vector A and A*B indicates dot
    // product of vectors A and B.

    // compute u0
    akVector[0].Unitize();

    // compute u1
    MgcReal fDot0 = akVector[0].Dot(akVector[1]); 
    akVector[1] -= fDot0*akVector[0];
    akVector[1].Unitize();
}
//----------------------------------------------------------------------------
